package ru.myrtle.umf.tools.ugen;

import ru.myrtle.umf.codegen.GenException;
import ru.myrtle.umf.codegen.GenTemplate;
import ru.myrtle.umf.codegen.Resource;
import ru.myrtle.umf.codegen.java.JavaDocAnnotation;
import ru.myrtle.umf.codegen.java.JavaDocBuilder;
import ru.myrtle.umf.codegen.java.JavaImportBuilder;

import java.io.Writer;

public abstract class UTemplate implements GenTemplate<UGenConfig> {

    protected final JavaDocBuilder docBuilder =
            new JavaDocBuilder();

    protected void reject() throws UTemplateRejectException {
        throw new UTemplateRejectException();
    }

    protected boolean checkObjectType(Object object, Class type) {
        return type != null && object != null && type.isAssignableFrom(object.getClass());
    }

    protected void checkTemplateObjectType(UTemplateContext context, Class type) throws UTemplateRejectException {
        boolean check = !checkObjectType(
                context.getObject(), type
        );

        if (check) {
            reject();
        }
    }

    protected void insertImport(StringBuffer buffer, JavaImportBuilder importBuilder, String namespace) {
        String separator = System.getProperties().getProperty("line.separator");

        int idx = buffer.indexOf(";");

        buffer.insert(idx + 1, separator);
        buffer.insert(idx + 2, separator + importBuilder.getFormattedImports(namespace));
    }

    protected void createDoc(String indent) {
        docBuilder.clean();
        docBuilder.setIndent(indent);
    }

    protected void createDoc() {
        docBuilder.clean();
    }

    protected void addDocDescription(String description) {
        docBuilder.append(description);
    }

    protected void addDocAnnotation(String name) {
        docBuilder.appendAnnotation(name);
    }

    protected void addDocAnnotation(JavaDocAnnotation annotation) {
        docBuilder.appendAnnotation(annotation);
    }

    protected void addDocAnnotation(String name, String entryName, String value) {
        docBuilder.appendAnnotation(name, entryName, value);
    }

    protected String getDocString() {
        return docBuilder.toString();
    }

    public abstract String generate(UTemplateContext context) throws UTemplateRejectException;

    @Override
    public String getName() {
        return getClass().getSimpleName();
    }

    @Override
    public boolean generate(Object object, Resource resource, UGenConfig config)
            throws GenException {

        UTemplateContext context = new UTemplateContext();

        context.setObject(object);
        context.setResource(resource);
        context.setConfig(config);

        try {
            String result = generate(
                    context
            );

            try {
                Writer writer = resource.getWriter();
                try {
                    writer.write(
                            result
                    );
                }
                finally {
                    writer.close();
                }
            }
            catch (Exception thrown) {
                throw new GenException(
                        thrown.getMessage(), thrown
                );
            }

            return true;
        }
        catch (UTemplateRejectException rejected) {
            return false;
        }
    }
}
